
package com.gitee.jmash.rbac.service;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import com.gitee.jmash.common.excel.ExcelExport;
import com.gitee.jmash.common.grpc.GrpcContext;
import com.gitee.jmash.common.security.JmashPrincipal;
import com.gitee.jmash.common.tree.Tree;
import com.gitee.jmash.common.utils.FreeMarkerUtil;
import com.gitee.jmash.common.utils.UUIDUtil;
import com.gitee.jmash.core.orm.cdi.JpaTenantService;
import com.gitee.jmash.core.orm.jpa.TenantEntityManager;
import com.gitee.jmash.core.orm.tenant.TenantService;
import com.gitee.jmash.core.transaction.JakartaTransaction;
import com.gitee.jmash.core.utils.FilePathUtil;
import com.gitee.jmash.itext.PdfUtils;
import com.gitee.jmash.rbac.dao.DeptDao;
import com.gitee.jmash.rbac.dao.UsersJobsDao;
import com.gitee.jmash.rbac.entity.DeptEntity;
import com.gitee.jmash.rbac.excel.DeptHeaderExport;
import com.gitee.jmash.rbac.model.TreeResult;
import jakarta.enterprise.inject.Typed;
import jakarta.enterprise.inject.spi.CDI;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;
import jakarta.transaction.Transactional.TxType;
import jakarta.validation.executable.ValidateOnExecution;
import jmash.protobuf.TableHead;
import jmash.protobuf.TenantReq;
import jmash.rbac.protobuf.DeptExportReq;
import jmash.rbac.protobuf.DeptReq;

/**
 * 组织机构 rbac_dept读服务.
 *
 * @author <a href="mailto:service@crenjoy.com">crenjoy</a>
 */
@Typed(DeptRead.class)
@Transactional(TxType.SUPPORTS)
@JpaTenantService
@ValidateOnExecution
public class DeptReadBean implements DeptRead, JakartaTransaction {

  protected TenantEntityManager tem = new TenantEntityManager();

  protected DeptDao deptDao = new DeptDao(this.tem);
  protected UsersJobsDao usersJobsDao = new UsersJobsDao(this.tem);

  @PersistenceContext(unitName = "ReadRbac")
  public void setEntityManager(EntityManager entityManager) {
    this.tem.setEntityManager(entityManager, false);
  }

  @Override
  public EntityManager getEntityManager() {
    return this.tem.getEntityManager();
  }

  @Override
  @SuppressWarnings("unchecked")
  public <T extends TenantService> T setTenant(String tenant) {
    this.tem.setTenant(tenant);
    return (T) this;
  }

  @Override
  public void setTenantOnly(String tenant) {
    this.tem.setTenantOnly(tenant);
  }

  @Override
  public String getTenant() {
    return this.tem.getTenant();
  }

  @Override
  public DeptEntity findById(UUID entityId) {
    return deptDao.find(entityId);
  }

  @Override
  public List<DeptEntity> findListByReq(DeptReq req) {
    Tree<DeptEntity, UUID> tree = findTreeByReq(req);
    List<DeptEntity> deptList = StringUtils.isNotBlank(req.getParentId())
        ? tree.getSelfChildsList(UUIDUtil.fromString(req.getParentId()))
        : tree.getAllList();
    return deptList;
  }

  /**
   * 查询部门信息树.
   */
  public Tree<DeptEntity, UUID> findTreeByReq(DeptReq req) {
    // 得到所有节点list信息然后放到内存树中
    Tree<DeptEntity, UUID> tree = new Tree<>();
    List<DeptEntity> deptList = deptDao.findListByReq(req);
    if (deptList.size() == 0) {
      return tree;
    }
    for (DeptEntity deptEntity : deptList) {
      tree.add(deptEntity.getDeptId(), deptEntity, deptEntity.getParentId(),
          deptEntity.getOrderBy());
    }
    return tree;
  }

  @Override
  public List<TreeResult> findTreeList(DeptReq req) {
    req = req.toBuilder().setHasStatus(true).setStatus(true).build();
    return deptDao.findTreeListByReq(req);
  }

  @Override
  public void close() throws Exception {
    CDI.current().destroy(this);
  }

  @Override
  public String downloadDeptTemplate(TenantReq request) throws FileNotFoundException, IOException {
    return exportDept(Collections.emptyList(), null, Collections.emptyList(), null);
  }

  private String exportDept(List<DeptEntity> deptList, String title, List<TableHead> tableHeads,
      String fileName) throws FileNotFoundException, IOException {
    ExcelExport excelExport = new ExcelExport();
    // 页签
    excelExport.createSheet(DeptHeaderExport.TITLE);
    // 增加表头
    DeptHeaderExport.addHeaderExport(excelExport, tableHeads);
    // 写标题
    title = StringUtils.isBlank(title) ? DeptHeaderExport.TITLE : title;
    excelExport.writeTitle(title);
    // 写表头
    excelExport.writeHeader();
    // 写数据
    excelExport.writeListData(deptList);
    // 增加数据校验
    excelExport.dictDataValidation(deptList.size(), 3000);
    // 写入文件
    fileName = StringUtils.isBlank(fileName) ? title : fileName;
    String fileSrc = FilePathUtil.createNewTempFile(fileName + ".xlsx", "excel");
    String realFileSrc = FilePathUtil.realPath(fileSrc,true);
    excelExport.getWb().write(new FileOutputStream(realFileSrc));
    return realFileSrc;
  }

  @Override
  public String exportDept(DeptExportReq request) throws FileNotFoundException, IOException {
    List<DeptEntity> list = findListByReq(request.getReq());
    return exportDept(list, request.getTitle(), request.getTableHeadsList(), request.getFileName());
  }

  @Override
  public String printDept(DeptExportReq req) throws FileNotFoundException, IOException {
    List<TableHead> tableHeads = req.getTableHeadsCount() > 0 ? req.getTableHeadsList()
        : DeptHeaderExport.getTableHeadList();
    List<DeptEntity> deptList = findListByReq(req.getReq());
    // 数据Map.
    Map<String, Object> dataMap = new HashMap<String, Object>();
    dataMap.put("tableHeads", tableHeads);
    dataMap.put("deptList", deptList);
    String title = StringUtils.isBlank(req.getTitle()) ? DeptHeaderExport.TITLE : req.getTitle();
    dataMap.put("title", title);
    dataMap.put("statusMap", DeptHeaderExport.getStatusMap());

    // 生成HTML.
    String htmlStr = FreeMarkerUtil.parse(DeptReadBean.class, dataMap, "/print/rbac_dept.ftl");
    // 文件路径
    String fileName = StringUtils.isBlank(req.getFileName()) ? title : req.getFileName();
    String fileSrc = FilePathUtil.createNewTempFile(fileName + ".pdf", "pdf");
    String realFileDir = FilePathUtil.realPath(fileSrc,true);
    // 登录用户
    JmashPrincipal principal = GrpcContext.getPrincipal();
    String realname = (principal != null) ? principal.getSubject() : "未登录";
    // PDF生成
    try (OutputStream outS = new FileOutputStream(realFileDir)) {
      PdfUtils.convertToPdf(htmlStr, outS, "", realname, true);
    }
    return realFileDir;
  }
}
